<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flood-It | Modern Puzzle Game</title>
    <style>
        :root {
            --primary-color: #2c3e50;
            --secondary-color: #34495e;
            --accent-color: #3498db;
            --text-light: #ecf0f1;
            --text-dark: #2c3e50;
            --shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        }

        body {
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ed 100%);
            margin: 0;
            padding: 0;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            color: var(--text-dark);
        }

        .header {
            width: 100%;
            background-color: var(--primary-color);
            color: var(--text-light);
            padding: 1.5rem 0;
            text-align: center;
            box-shadow: var(--shadow);
            margin-bottom: 2rem;
            position: relative;
        }

        .header h1 {
            margin: 0;
            font-weight: 600;
            letter-spacing: 0.5px;
            font-size: 2.2rem;
        }

        .header::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 4px;
            background: linear-gradient(90deg, #3498db, #2ecc71, #f1c40f, #e74c3c, #9b59b6);
        }

        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 2rem;
            max-width: 1200px;
            width: 100%;
            padding: 0 2rem;
        }

        .game-info {
            display: flex;
            justify-content: space-between;
            width: 100%;
            max-width: 600px;
            background-color: white;
            padding: 1.2rem 2rem;
            border-radius: 12px;
            box-shadow: var(--shadow);
            border: 1px solid rgba(0, 0, 0, 0.05);
        }

        .info-item {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .info-label {
            font-size: 0.85rem;
            color: #7f8c8d;
            margin-bottom: 0.3rem;
            font-weight: 500;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .info-value {
            font-size: 1.8rem;
            font-weight: 700;
            color: var(--primary-color);
            font-feature-settings: "tnum";
        }

        .board-container {
            position: relative;
            margin: 1rem 0;
            padding: 10px;
            background: white;
            border-radius: 12px;
            box-shadow: var(--shadow);
            border: 1px solid rgba(0, 0, 0, 0.05);
        }

        .board {
            display: grid;
            gap: 2px;
            background-color: var(--secondary-color);
            padding: 4px;
            border-radius: 6px;
            box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1);
        }

        .cell {
            width: 28px;
            height: 28px;
            cursor: pointer;
            transition: var(--transition);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: rgba(0, 0, 0, 0.3);
            position: relative;
            overflow: hidden;
            border-radius: 3px;
        }

        .cell.black-cell {
            background-color: #000 !important;
            cursor: not-allowed;
        }

        .cell::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: currentColor;
            opacity: 0;
            transition: var(--transition);
        }

        .cell:hover::after {
            opacity: 0.1;
        }

        .cell.flooded {
            box-shadow: inset 0 0 0 2px white, 
                        inset 0 0 10px rgba(255, 255, 255, 0.5);
            transform: scale(1);
        }

        .cell.flood-animation {
            animation: floodPulse 0.6s ease-out;
        }

        @keyframes floodPulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.1); }
            100% { transform: scale(1); }
        }

        .controls {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 1.5rem;
            margin-bottom: 2rem;
            width: 100%;
        }

        .control-group {
            background-color: white;
            padding: 1.5rem;
            border-radius: 12px;
            box-shadow: var(--shadow);
            border: 1px solid rgba(0, 0, 0, 0.05);
            min-width: 250px;
        }

        .control-title {
            margin-top: 0;
            margin-bottom: 1.2rem;
            font-size: 1.1rem;
            color: var(--primary-color);
            text-align: center;
            font-weight: 600;
        }

        select, button {
            padding: 0.7rem 1.2rem;
            border: none;
            border-radius: 8px;
            background-color: var(--accent-color);
            color: white;
            cursor: pointer;
            transition: var(--transition);
            font-size: 0.95rem;
            font-weight: 500;
            width: 100%;
            margin-bottom: 0.8rem;
        }

        select {
            background-color: white;
            color: var(--text-dark);
            border: 1px solid #dfe6e9;
            appearance: none;
            background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
            background-repeat: no-repeat;
            background-position: right 0.7rem center;
            background-size: 1rem;
        }

        button {
            background: linear-gradient(135deg, #3498db, #2980b9);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
        }

        button:active {
            transform: translateY(0);
        }

        .checkbox-container {
            display: flex;
            align-items: center;
            margin-bottom: 1rem;
        }

        .checkbox-container input {
            margin-right: 0.5rem;
        }

        .color-options {
            display: flex;
            gap: 0.8rem;
            margin-top: 1.2rem;
            justify-content: center;
            flex-wrap: wrap;
        }

        .color-option {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            cursor: pointer;
            border: 3px solid transparent;
            transition: var(--transition);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            position: relative;
        }

        .color-option:hover {
            transform: scale(1.1);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
        }

        .color-option.selected {
            border-color: white;
            transform: scale(1.15);
            box-shadow: 0 0 0 3px var(--primary-color),
                        0 4px 8px rgba(0, 0, 0, 0.2);
        }

        .color-option.selected::after {
            content: '';
            position: absolute;
            top: -6px;
            left: -6px;
            right: -6px;
            bottom: -6px;
            border-radius: 50%;
            border: 2px solid var(--primary-color);
            animation: colorSelectPulse 1.5s infinite;
        }

        @keyframes colorSelectPulse {
            0% { opacity: 0.7; transform: scale(1); }
            50% { opacity: 0.3; transform: scale(1.05); }
            100% { opacity: 0.7; transform: scale(1); }
        }

        .modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 100;
            opacity: 0;
            pointer-events: none;
            transition: var(--transition);
        }

        .modal.active {
            opacity: 1;
            pointer-events: all;
        }

        .modal-content {
            background-color: white;
            padding: 3rem;
            border-radius: 16px;
            text-align: center;
            max-width: 450px;
            width: 90%;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            transform: translateY(-20px);
            transition: var(--transition);
            position: relative;
            overflow: hidden;
        }

        .modal.active .modal-content {
            transform: translateY(0);
        }

        .modal h2 {
            margin-top: 0;
            color: var(--primary-color);
            font-size: 2rem;
            margin-bottom: 1rem;
        }

        .modal p {
            font-size: 1.1rem;
            color: #555;
            margin-bottom: 1.5rem;
            line-height: 1.6;
        }

        .modal button {
            margin-top: 1rem;
            padding: 0.9rem 1.8rem;
            font-size: 1rem;
            border-radius: 8px;
        }

        .win-button {
            background: linear-gradient(135deg, #2ecc71, #27ae60);
        }

        .lose-button {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
        }

        .confetti {
            position: absolute;
            width: 10px;
            height: 10px;
            background-color: #f00;
            opacity: 0;
        }

        @media (max-width: 768px) {
            .game-info {
                flex-direction: column;
                gap: 1.2rem;
            }
          
            .cell {
                width: 22px;
                height: 22px;
            }

            .control-group {
                padding: 1.2rem;
            }

            .header h1 {
                font-size: 1.8rem;
            }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>Flood-It</h1>
    </div>

    <div class="game-container">
        <div class="game-info">
            <div class="info-item">
                <span class="info-label">Moves</span>
                <span class="info-value" id="moves">0</span>
            </div>
            <div class="info-item">
                <span class="info-label">Remaining</span>
                <span class="info-value" id="remaining">0</span>
            </div>
            <div class="info-item">
                <span class="info-label">Best</span>
                <span class="info-value" id="best">-</span>
            </div>
        </div>

        <div class="board-container">
            <div class="board" id="board"></div>
        </div>

        <div class="controls">
            <div class="control-group">
                <h3 class="control-title">Game Options</h3>
                <div>
                    <label for="grid-size">Grid Size:</label>
                    <select id="grid-size">
                        <option value="6">6×6</option>
                        <option value="8">8×8</option>
                        <option value="10">10×10</option>
                        <option value="14" selected>14×14</option>
                        <option value="20">20×20</option>
                    </select>
                </div>
                <div>
                    <label for="color-count">Colors:</label>
                    <select id="color-count">
                        <option value="4">4</option>
                        <option value="5">5</option>
                        <option value="6" selected>6</option>
                        <option value="7">7</option>
                        <option value="8">8</option>
                    </select>
                </div>
                <div class="checkbox-container">
                    <input type="checkbox" id="black-cells">
                    <label for="black-cells">Include unchangeable black cells</label>
                </div>
                <div>
                    <button id="new-game">New Game</button>
                </div>
            </div>

            <div class="control-group">
                <h3 class="control-title">Current Color</h3>
                <div class="color-options" id="color-options"></div>
            </div>
        </div>
    </div>

    <div class="modal" id="win-modal">
        <div class="modal-content">
            <h2>Congratulations!</h2>
            <p>You've flooded the entire board in <span id="final-moves">0</span> moves.</p>
            <p id="new-best" style="display: none; font-weight: 600; color: #27ae60;">🎉 New best score! 🎉</p>
            <button id="play-again" class="win-button">Play Again</button>
        </div>
    </div>

    <div class="modal" id="lose-modal">
        <div class="modal-content">
            <h2>Game Over!</h2>
            <p>You've reached the move limit without flooding the entire board.</p>
            <button id="try-again" class="lose-button">Try Again</button>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // Game state
            let board = [];
            let flooded = [];
            let currentColor = 0;
            let moves = 0;
            let moveLimit = 0;
            let bestScores = {};
            let gameActive = false;
            let colorChangeInProgress = false;
            let hasBlackCells = false;
          
            // DOM elements
            const boardElement = document.getElementById('board');
            const movesElement = document.getElementById('moves');
            const remainingElement = document.getElementById('remaining');
            const bestElement = document.getElementById('best');
            const gridSizeSelect = document.getElementById('grid-size');
            const colorCountSelect = document.getElementById('color-count');
            const blackCellsCheckbox = document.getElementById('black-cells');
            const newGameButton = document.getElementById('new-game');
            const colorOptionsElement = document.getElementById('color-options');
            const winModal = document.getElementById('win-modal');
            const loseModal = document.getElementById('lose-modal');
            const finalMovesElement = document.getElementById('final-moves');
            const newBestElement = document.getElementById('new-best');
            const playAgainButton = document.getElementById('play-again');
            const tryAgainButton = document.getElementById('try-again');
          
            // Color palette (high contrast colors)
            const colorPalette = [
                '#CC3333', // 低饱和红
                '#3366CC', // 低饱和蓝
                '#66CC66', // 低饱和绿
                '#FFEE99', // 低饱和黄
                '#CC66CC', // 低饱和品红
                '#66CCCC', // 低饱和青
                '#FF9966', // 低饱和橙
                '#336633', // 低饱和深绿
                '#663399', // 低饱和紫
                '#8B4513'  // 低饱和棕
            ];
          
            // Initialize game
            function initGame() {
                const size = parseInt(gridSizeSelect.value);
                const colorCount = parseInt(colorCountSelect.value);
                hasBlackCells = blackCellsCheckbox.checked;
              
                // Calculate move limit (based on size and color count)
                moveLimit = Math.floor(size * 1.5 + colorCount * 2);
                remainingElement.textContent = moveLimit;
                moves = 0;
                movesElement.textContent = moves;
              
                // Generate board
                board = generateBoard(size, colorCount, hasBlackCells);
                flooded = Array(size).fill().map(() => Array(size).fill(false));
              
                // Flood the starting area (skip if it's a black cell)
                if (board[0][0] !== -1) {
                    flood(0, 0, board[0][0]);
                    currentColor = board[0][0];
                } else {
                    // Find the first non-black cell to start
                    let found = false;
                    for (let x = 0;
                    x < board.length && !found; x++) {
                        for (let y = 0; y < board.length && !found; y++) {
                        if (board[x][y] !== -1) {
                            flood(x, y, board[x][y]);
                            currentColor = board[x][y];
                            found = true;
                            }
                        }                       
                    }
                }
            // Update UI
            renderBoard();
            updateColorOptions(colorCount);
            
            // Get best score for this configuration
            const configKey = `${size}-${colorCount}-${hasBlackCells}`;
            const bestScore = bestScores[configKey] || null;
            bestElement.textContent = bestScore !== null ? bestScore : '-';
            
            gameActive = true;
            colorChangeInProgress = false;
        }
        
        // Generate random board with optional black cells
        function generateBoard(size, colorCount, includeBlack) {
            const board = Array(size).fill().map(() => 
                Array(size).fill().map(() => 
                    Math.floor(Math.random() * colorCount)
                )
            );
            
            if (includeBlack) {
                // Add 5-10% black cells randomly
                const blackCellCount = Math.floor(size * size * (0.05 + Math.random() * 0.05));
                for (let i = 0; i < blackCellCount; i++) {
                    const x = Math.floor(Math.random() * size);
                    const y = Math.floor(Math.random() * size);
                    board[x][y] = -1; // -1 represents black cells
                }
            }
            
            return board;
        }
        
        // Flood fill algorithm
        function flood(x, y, targetColor) {
            if (x < 0 || y < 0 || x >= board.length || y >= board.length) return;
            if (flooded[x][y]) return;
            if (board[x][y] === -1) return; // Skip black cells
            if (board[x][y] !== targetColor) return;
            
            flooded[x][y] = true;
            
            // 4-way flood for square grid
            flood(x + 1, y, targetColor);
            flood(x - 1, y, targetColor);
            flood(x, y + 1, targetColor);
            flood(x, y - 1, targetColor);
        }
        
        // Change the flood color with animation
        async function changeColor(newColor) {
            if (newColor === currentColor) return; // Invalid move
            if (!gameActive || colorChangeInProgress) return;
            
            colorChangeInProgress = true;
            
            // Find all cells that will be flooded
            let cellsToFlood = [];
            for (let x = 0; x < board.length; x++) {
                for (let y = 0; y < board.length; y++) {
                    if (flooded[x][y] && board[x][y] !== -1) {
                        // Check adjacent cells
                        if (x > 0 && !flooded[x-1][y] && board[x-1][y] === newColor) cellsToFlood.push([x-1, y]);
                        if (x < board.length-1 && !flooded[x+1][y] && board[x+1][y] === newColor) cellsToFlood.push([x+1, y]);
                        if (y > 0 && !flooded[x][y-1] && board[x][y-1] === newColor) cellsToFlood.push([x, y-1]);
                        if (y < board.length-1 && !flooded[x][y+1] && board[x][y+1] === newColor) cellsToFlood.push([x, y+1]);
                    }
                }
            }
            
            // If no new cells would be flooded, it's an invalid move
            if (cellsToFlood.length === 0) {
                colorChangeInProgress = false;
                return;
            }
            
            // Update current color
            currentColor = newColor;
            moves++;
            movesElement.textContent = moves;
            remainingElement.textContent = Math.max(0, moveLimit - moves);
            
            // Update color options UI
            updateColorOptions(colorCountSelect.value);
            
            // Change all flooded cells to the new color immediately
            for (let x = 0; x < board.length; x++) {
                for (let y = 0; y < board.length; y++) {
                    if (flooded[x][y] && board[x][y] !== -1) {
                        board[x][y] = newColor;
                        const cellIndex = x * board.length + y;
                        const cellElement = boardElement.children[cellIndex];
                        if (cellElement) {
                            cellElement.style.backgroundColor = colorPalette[newColor];
                        }
                    }
                }
            }
            
            // Animate the flood
            await animateFlood(cellsToFlood, newColor);
            
            // Check win condition
            if (checkWin()) {
                endGame(true);
            } else if (moves >= moveLimit) {
                endGame(false);
            }
            
            colorChangeInProgress = false;
        }
        
        // Animate the flood process
        async function animateFlood(cells, newColor) {
            // First pass: animate the color change of border cells
            const animations = [];
            
            for (const [x, y] of cells) {
                flooded[x][y] = true;
                const cellIndex = x * board.length + y;
                const cellElement = boardElement.children[cellIndex];
                
                if (cellElement) {
                    cellElement.classList.add('flood-animation');
                    animations.push(
                        new Promise(resolve => {
                            setTimeout(() => {
                                cellElement.style.backgroundColor = colorPalette[newColor];
                                cellElement.classList.add('flooded');
                                resolve();
                            }, 100);
                        })
                    );
                }
            }
            
            await Promise.all(animations);
            
            // Second pass: remove animation class after a delay
            setTimeout(() => {
                for (const [x, y] of cells) {
                    const cellIndex = x * board.length + y;
                    const cellElement = boardElement.children[cellIndex];
                    if (cellElement) {
                        cellElement.classList.remove('flood-animation');
                    }
                }
            }, 300);
            
            // Continue flooding recursively for any new adjacent cells
            let newCellsToFlood = [];
            for (const [x, y] of cells) {
                if (x > 0 && !flooded[x-1][y] && board[x-1][y] === newColor) newCellsToFlood.push([x-1, y]);
                if (x < board.length-1 && !flooded[x+1][y] && board[x+1][y] === newColor) newCellsToFlood.push([x+1, y]);
                if (y > 0 && !flooded[x][y-1] && board[x][y-1] === newColor) newCellsToFlood.push([x, y-1]);
                if (y < board.length-1 && !flooded[x][y+1] && board[x][y+1] === newColor) newCellsToFlood.push([x, y+1]);
            }
            
            // Remove duplicates
            newCellsToFlood = Array.from(new Set(newCellsToFlood.map(JSON.stringify))).map(JSON.parse);
            
            if (newCellsToFlood.length > 0) {
                await animateFlood(newCellsToFlood, newColor);
            }
        }
        
        // Check if the player has won
        function checkWin() {
            for (let x = 0; x < board.length; x++) {
                for (let y = 0; y < board.length; y++) {
                    if (!flooded[x][y] && board[x][y] !== -1) return false;
                }
            }
            return true;
        }
        
        // End the game
        function endGame(win) {
            gameActive = false;
            
            if (win) {
                const size = parseInt(gridSizeSelect.value);
                const colorCount = parseInt(colorCountSelect.value);
                const configKey = `${size}-${colorCount}-${hasBlackCells}`;
                
                // Update best score
                if (!bestScores[configKey] || moves < bestScores[configKey]) {
                    bestScores[configKey] = moves;
                    newBestElement.style.display = 'block';
                    createConfetti();
                } else {
                    newBestElement.style.display = 'none';
                }
                
                finalMovesElement.textContent = moves;
                winModal.classList.add('active');
            } else {
                loseModal.classList.add('active');
            }
        }
        
        // Create confetti effect
        function createConfetti() {
            const colors = ['#FF0000', '#0000FF', '#00FF00', '#FFFF00', '#FF00FF', '#00FFFF'];
            const modalContent = document.querySelector('.modal-content');
            
            for (let i = 0; i < 100; i++) {
                const confetti = document.createElement('div');
                confetti.className = 'confetti';
                confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
                confetti.style.left = Math.random() * 100 + '%';
                confetti.style.top = -10 + 'px';
                confetti.style.width = Math.random() * 8 + 4 + 'px';
                confetti.style.height = Math.random() * 8 + 4 + 'px';
                confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0';
                modalContent.appendChild(confetti);
                
                const animationDuration = Math.random() * 3 + 2;
                
                confetti.animate([
                    { top: '-10px', opacity: 0, transform: 'rotate(0deg)' },
                    { opacity: 1 },
                    { top: '100%', opacity: 0, transform: 'rotate(' + (Math.random() * 360) + 'deg)' }
                ], {
                    duration: animationDuration * 1000,
                    easing: 'cubic-bezier(0.1, 0.8, 0.9, 1)',
                    delay: Math.random() * 2000
                });
                
                setTimeout(() => {
                    confetti.remove();
                }, animationDuration * 1000);
            }
        }
        
        // Render the board
        function renderBoard() {
            boardElement.innerHTML = '';
            boardElement.style.gridTemplateColumns = `repeat(${board.length}, 1fr)`;
            
            for (let x = 0; x < board.length; x++) {
                for (let y = 0; y < board.length; y++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    
                    if (board[x][y] === -1) {
                        cell.classList.add('black-cell');
                    } else {
                        cell.style.backgroundColor = colorPalette[board[x][y]];
                    }
                    
                    if (flooded[x][y]) {
                        cell.classList.add('flooded');
                    }
                    
                    cell.addEventListener('click', () => {
                        if (gameActive && !colorChangeInProgress && board[x][y] !== -1) changeColor(board[x][y]);
                    });
                    
                    boardElement.appendChild(cell);
                }
            }
        }
        
        // Update color options display
        function updateColorOptions(colorCount) {
            colorOptionsElement.innerHTML = '';
            
            for (let i = 0; i < colorCount; i++) {
                const colorOption = document.createElement('div');
                colorOption.className = `color-option ${i === currentColor ? 'selected' : ''}`;
                colorOption.style.backgroundColor = colorPalette[i];
                colorOption.addEventListener('click', () => {
                    if (gameActive && !colorChangeInProgress && i !== currentColor) changeColor(i);
                });
                colorOptionsElement.appendChild(colorOption);
            }
        }
        
        // Event listeners
        newGameButton.addEventListener('click', initGame);
        playAgainButton.addEventListener('click', () => {
            winModal.classList.remove('active');
            initGame();
        });
        tryAgainButton.addEventListener('click', () => {
            loseModal.classList.remove('active');
            initGame();
        });
        
        // Initialize on load
        initGame();
    });
</script>
